﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Security;
using System.Security.Principal;
using System.Threading;
using System.Runtime.InteropServices;
using Tools;


namespace MtwControl
{
    public class Ps2
    {
        [DllImport("user32", EntryPoint = "MapVirtualKey")]
        public static extern int MapVirtualKey(int wCode, int wMapType);

        private Ols ols;
        private static Log log;
        private static int delayDown = 5;
        private static int delayPress = 5;
        private static int delayUp = 1;

        public Ps2()
        {
            log = new Log(this);
            if (!this.IsAdmin())
            {
                log.debug("current user is not administrator");
                Environment.Exit(0);
                log.debug("application exit");
            }
            log.debug("current user is administrator");
            this.Init();
        }

        /// <summary>
        /// 判断是否是管理员
        /// </summary>
        /// <returns></returns>
        private bool IsAdmin()
        {
            OperatingSystem osInfo = Environment.OSVersion;
            if (osInfo.Platform == PlatformID.Win32Windows)
            {
                return true;
            }
            else
            {
                WindowsIdentity usrId = WindowsIdentity.GetCurrent();
                WindowsPrincipal p = new WindowsPrincipal(usrId);
                return p.IsInRole(@"BUILTIN\Administrators");
            }
        }

        /// <summary>
        /// 初始化
        /// </summary>
        unsafe private void Init()
        {
            try
            {
                ols = new Ols();
                // Check support library sutatus
                log.debug("Check support library sutatus");
                switch (ols.GetStatus())
                {
                    case (uint)Ols.Status.NO_ERROR:
                        log.debug("Check support library NO_ERROR");
                        break;
                    case (uint)Ols.Status.DLL_NOT_FOUND:
                        log.error("Status Error!! DLL_NOT_FOUND");
                        Environment.Exit(0);
                        break;
                    case (uint)Ols.Status.DLL_INCORRECT_VERSION:
                        log.error("Status Error!! DLL_INCORRECT_VERSION");
                        break;
                    case (uint)Ols.Status.DLL_INITIALIZE_ERROR:
                        log.error("Status Error!! DLL_INITIALIZE_ERROR");
                        break;
                }
                // Check WinRing0 status
                log.debug("Check WinRing0 status");
                switch (ols.GetDllStatus())
                {
                    case (uint)Ols.OlsDllStatus.OLS_DLL_NO_ERROR:
                        log.debug("Check WinRing0 status OLS_DLL_NO_ERROR");
                        break;
                    case (uint)Ols.OlsDllStatus.OLS_DLL_DRIVER_NOT_LOADED:
                        log.error("DLL Status Error!! OLS_DRIVER_NOT_LOADED");
                        Environment.Exit(0);
                        break;
                    case (uint)Ols.OlsDllStatus.OLS_DLL_UNSUPPORTED_PLATFORM:
                        log.error("DLL Status Error!! OLS_UNSUPPORTED_PLATFORM");
                        Environment.Exit(0);
                        break;
                    case (uint)Ols.OlsDllStatus.OLS_DLL_DRIVER_NOT_FOUND:
                        log.error("DLL Status Error!! OLS_DLL_DRIVER_NOT_FOUND");
                        Environment.Exit(0);
                        break;
                    case (uint)Ols.OlsDllStatus.OLS_DLL_DRIVER_UNLOADED:
                        log.error("DLL Status Error!! OLS_DLL_DRIVER_UNLOADED");
                        Environment.Exit(0);
                        break;
                    case (uint)Ols.OlsDllStatus.OLS_DLL_DRIVER_NOT_LOADED_ON_NETWORK:
                        log.error("DLL Status Error!! DRIVER_NOT_LOADED_ON_NETWORK");
                        Environment.Exit(0);
                        break;
                    case (uint)Ols.OlsDllStatus.OLS_DLL_UNKNOWN_ERROR:
                        log.error("DLL Status Error!! OLS_DLL_UNKNOWN_ERROR");
                        Environment.Exit(0);
                        break;
                }
                log.debug("Check DLL Information");
                String str = "";
                //-----------------------------------------------------------------------------
                // DLL Information
                //-----------------------------------------------------------------------------
                byte major = 0, minor = 0, revision = 0, release = 0;
                str += "[DLL Version]";
                ols.GetDllVersion(ref major, ref minor, ref revision, ref release);
                str += major.ToString()
                    + "." + minor.ToString()
                    + "." + revision.ToString()
                    + "." + release.ToString();
                log.debug(str);
                str = "[Device Driver Version]";
                ols.GetDriverVersion(ref major, ref minor, ref revision, ref release);
                str += major.ToString()
                    + "." + minor.ToString()
                    + "." + revision.ToString()
                    + "." + release.ToString();
                log.debug(str);
                str = "[Device Driver Type]";
                switch (ols.GetDriverType())
                {
                    case (uint)Ols.OlsDriverType.OLS_DRIVER_TYPE_WIN_9X:
                        str += "OLS_DRIVER_TYPE_WIN_9X";
                        break;
                    case (uint)Ols.OlsDriverType.OLS_DRIVER_TYPE_WIN_NT:
                        str += "OLS_DRIVER_TYPE_WIN_NT";
                        break;
                    case (uint)Ols.OlsDriverType.OLS_DRIVER_TYPE_WIN_NT_X64:
                        str += "OLS_DRIVER_TYPE_WIN_NT_X64";
                        break;
                    case (uint)Ols.OlsDriverType.OLS_DRIVER_TYPE_WIN_NT_IA64:
                        str += "OLS_DRIVER_TYPE_WIN_NT_IA64";
                        break;
                    default:
                        str += "OLS_DRIVER_TYPE_UNKNOWN";
                        break;
                }
                log.debug(str);
            }
            catch (Exception e)
            {
                log.error(e.ToString());
            }
        }

        /// <summary>
        /// keydown
        /// </summary>
        /// <param name="key"></param>
        public void keyDown(byte key)
        {
            writeKeyDown(key);
            delay(delayDown);
        }
        /// <summary>
        /// keyup
        /// </summary>
        /// <param name="key"></param>
        public void keyUp(byte key)
        {
            writeKeyUp(key);
            delay(delayUp);
        }

        private void writeKeyUp(byte vkey)
        {
            if (vkey == 13)
            {
                writeScanKey(0xE0);
            }
            byte scancode = Convert.ToByte(MapVirtualKey(vkey, 0));
            writeScanKey(Convert.ToByte(scancode | 0x80));

        }
        private void delay(int delayDown1)
        {
            Thread.Sleep(delayDown1);
        }
        private void writeKeyDown(byte vkey)
        {
            /* if(VK_EXT2[vkey]) {
             * NUMPAD_ENTER=13
             * VK_EXT2 = {
                NUMPAD_ENTER=1; 
            }*/
            if (vkey == 13)
            {
                writeScanKey(0xE0);
            }
            byte scancode = Convert.ToByte(MapVirtualKey(vkey, 0));
            writeScanKey(scancode);
        }
        private void writeScanKey(byte chr)
        {
            waitOutputEmpty(); //等待OBF空闲
            waitInputEmpty(); //等待IBF空闲
            _outp_char(0x64, 0xd2);
            waitInputEmpty(); //等待芯版读取指令并清空IBF
            _outp_char(0x60, chr);
            waitInputEmpty(); //等待芯版读取数据并清空IBF
            waitOutputEmpty(); //等侍系统读取并清空OBF
        }
        private void waitOutputEmpty()
        {
            byte __b;
            do
            {
                Thread.Sleep(1);
                __b = _inp_char(0x64);
            } while (Convert.ToBoolean(__b & 0x01));
        }
        private void waitInputEmpty()
        {
            byte __b;
            do
            {
                Thread.Sleep(1);
                __b = _inp_char(0x64);
            } while (Convert.ToBoolean(__b & 0x02));
        }
        /// <summary>
        /// 写数据
        /// </summary>
        /// <param name="port"></param>
        /// <param name="value"></param>
        private void _outp_char(ushort port, byte value)
        {
            ols.WriteIoPortByte(port, value);
        }
        /// <summary>
        /// 读数据
        /// </summary>
        /// <param name="port"></param>
        private byte _inp_char(ushort port)
        {
            return ols.ReadIoPortByte(port);
        }
    }
}
